'use strict';

const ConnectOption = require('../oltmodules/ConnectOption');
const ZTEOLT = require('../oltmodules/ZTEOLT');
const HWOLT = require('../oltmodules/HuaWeiOLT');
const ulid = require('../public/ulid');
// const olt = require('../routers/olt');
const XDOLT = require('../oltmodules/XinDeOLT');
const XGLOLT = require('../oltmodules/XinGeLinOLT');
const sequelize = require('sequelize');
const Service = require('egg').Service;

class OnuService extends Service {
  async getOnuNums(params) {
    const result = {};
    const where = {};
    where.tid = params.tid;
    result.count = await this.ctx.model.OnuList.find(where).count('_id');
    return result;
  }
  async list(params) {
    const tid = params.tid;
    const Op = this.ctx.model.Sequelize.Op;
    let where = {};
    if (params.OltId) {
      where.oltId = params.OltId;
    }
    if (params.state) {
      where.state = params.state;
    }
    if (params.PONindex) {
      where.PONindex = { [Op.like]: '%' + params.PONindex };
    }
    if (params.search) {
      where = {
        [Op.or]: [{ ONUname: { [Op.like]: '%' + params.search + '%' } },
          { SN: { [Op.like]: '%' + params.search + '%' } },
        ],
      };
    }
    return await this.ctx.model.Onu.findAndCountAll({
      where,
      offset: parseInt((params.page - 1) * params.limit),
      limit: parseInt(params.limit),
      include: [{
        model: this.ctx.model.Olt,
        where: {
          tid,
        },
      }, { model: this.ctx.model.User }],
      order: [
        [ this.ctx.model.Olt, 'oltIP', 'ASC' ],
        [ 'S', 'ASC' ],
        [ 'P', 'ASC' ],
        sequelize.cast(sequelize.col('ONUindex'), 'SIGNED'),
      ],
    });
  }
  async refresh(params) {
    let result;
    const tid = params.tid;
    if (params.OltId) {
      const olt = await this.ctx.model.Olt.findOne({
        where: { id: params.OltId },
      });
      result = await refreshONU(olt, this);
      return result;
    }
    const msg = {
      fail: '',
      success: '',
    };
    const AllOlt = await this.ctx.model.Olt.findAll({
      where: { tid },
    });
    for (let i = 0; i < AllOlt.length; i++) {
      result = await refreshONU(AllOlt[i], this);
      if (result.flag == false) {
        msg.fail += result.msg;
      } else {
        msg.success += result.msg;
      }
    }
    return msg.success + msg.fail;

  }
  async delete(params) {
    const onuResult = await this.ctx.model.OnuList.findOne({ _id: params.id });
    const oltResult = await this.ctx.model.Olt.findOne({ _id: onuResult.oltId });
    global.log.desc = `${oltResult.name} ${oltResult.oltIP} delete onu onuID:${onuResult.PONindex + ':' + onuResult.ONUindex} SN:${onuResult.SN}`;
    const options = new ConnectOption(oltResult.oltIP, oltResult.initCommunity, oltResult.snmpUDPPort, 162, true, true, oltResult.telnetTCPPort, oltResult.oltManagementPassword, oltResult.oltTelnetUsername, oltResult.oltTelnetPassword, oltResult.systemName, oltResult.RZUsername, oltResult.RZPassword,oltResult.telnetProxySwitch);
    const result = {
      msg: '',
    };
    try {
      switch (oltResult.oltType) {
        case 'OPTICTIMES':
        { const xd = new XDOLT(options);
          await xd.deleteONU(onuResult.PONindex, onuResult.ONUindex, oltResult.oltHardVersion, this);
          break; }
        case 'ZTE':
        { const zte = new ZTEOLT(options);
          const PONOLTName = onuResult.PONindex.replace('onu', 'olt');
          await zte.deleteONU(PONOLTName, onuResult.ONUindex, oltResult.oltHardVersion, this);
          break; }
        case 'HUAWEI':
        { const hw = new HWOLT(options);
          const serviceport = await hw.getOnuServicePort(onuResult.PONindex, onuResult.ONUindex, 'NONE', this);
          await hw.deleteONU(onuResult.PONindex, onuResult.ONUindex, serviceport, 'NONE', this);
          break; }
        case 'XINGELIN':
        { const xgl = new XGLOLT(options);
          await xgl.deleteONU(onuResult.PONindex, onuResult.ONUindex, oltResult.oltHardVersion, this);
          break; }
        default:
          break;
      }
      await this.ctx.model.OnuList.deleteOne({ _id: params.id });
      result.msg = 'delete ONU successful';
      return result;
    } catch (error) {
      result.msg = 'delete ONU fail,' + error;
      return result;
    }
  }
  async bind(params) {
    const result = {
      msg: '',
    };
    try {
      await this.ctx.model.Onu.update({ userId: params.userId }, { where: { id: params.id } });
      await this.ctx.model.User.update({ onuId: params.id }, { where: { id: params.userId } });
      result.msg = 'onu bind user successful';
      return result;
    } catch (error) {
      result.msg = 'onu bind user fail,' + error;
      return result;
    }
  }
  async unbind(params) {
    const result = {
      msg: '',
    };
    try {
      const onuResult = await this.ctx.model.Onu.findOne({ where: { id: params.id } });
      await this.ctx.model.Onu.update({ userId: null }, { where: { id: params.id } });
      await this.ctx.model.User.update({ onuId: null }, { where: { id: onuResult.userId } });
      result.msg = 'onu unbind user successful';
      return result;
    } catch (error) {
      result.msg = 'onu unbind user fail,' + error;
      return result;
    }
  }
  async onuBindVlan(olt, ponIndex, onuIndex, vlan, upstream, downstream, lineProfile, srvProfile) { // 2.根据品牌，做不同的处理
    const findMaxDBA = function(dba) {
      let type1 = [],
        type2 = [],
        type3 = [],
        type4 = [],
        type5 = [];
      for (let i = 0; i < dba.length; i++) {
        switch (dba[i].type) {
          case '1':// 固定带宽
            type1.push(dba[i]);
            break;
          case '2':// 保证带宽
            type2.push(dba[i]);
            break;
          case '3':// 保证带宽+最大带
            type3.push(dba[i]);
            break;
          case '4':// 最大带宽
            type4.push(dba[i]);
            break;
          case '5':// 固定带宽+保证带宽+最大带宽
            type5.push(dba[i]);
            break;
        }
      }
      function mySort(arr, key) {
        arr.sort((a, b) => {
          if (parseInt(a[key]) < parseInt(b[key])) { // 按某种排序标准进行比较, a 小于 b
            return -1;
          }
          if (parseInt(a[key]) > parseInt(b[key])) {
            return 1;
          }
          // a must be equal to b
          return 0;
        });
        return arr;
      }
      type1 = mySort(type1, 'FBW');
      type2 = mySort(type2, 'ABW');
      type3 = mySort(type3, 'ABW');
      type4 = mySort(type4, 'MBW');
      type5 = mySort(type5, 'ABW');
      // 优先ABW，其次MBW，最后FBW
      if (type2.length > 0) {
        return type2[type2.length - 1].name || type2[type2.length - 1].Name || type2[type2.length - 1].NAME;
      }
      if (type3.length > 0) {
        return type3[type3.length - 1].name || type3[type3.length - 1].Name || type3[type3.length - 1].NAME;
      }
      if (type5.length > 0) {
        return type5[type5.length - 1].name || type5[type5.length - 1].Name || type5[type5.length - 1].NAME;
      }
      if (type4.length > 0) {
        return type4[type4.length - 1].name || type4[type4.length - 1].Name || type4[type4.length - 1].NAME;
      }
      if (type5.length > 0) {
        return type5[type5.length - 1].name || type5[type5.length - 1].Name || type5[type5.length - 1].NAME;
      }
    };
    const Strategy = function(brandName, olt) {
      console.log('当前要绑定vlan=', vlan);
      const Brand = {
        async ZTE() {
          const options = new ConnectOption(olt.oltIP, olt.initCommunity, olt.snmpUDPPort, 162, true, true, olt.telnetTCPPort, olt.oltManagementPassword, olt.oltTelnetUsername, olt.oltTelnetPassword, olt.systemName, olt.RZUsername, olt.RZPassword,olt.telnetProxySwitch);
          const zte = new ZTEOLT(options);
          const dbaInfo = await zte.getDbaProfile_ZTE(olt.oltHardVersion, this);
          const dba = findMaxDBA(dbaInfo);
          console.log('查询到DBA数据:', dbaInfo, '最大的DBA=', dba);
          console.log(`查询onu：${ponIndex}:${onuIndex}`);
          const preInfo = await zte.getOnuBindInfo(olt.oltHardVersion, ponIndex, onuIndex, this);
          console.log('查询到tcount|gemport|vport|servicePort:', preInfo);
          const { tcontMax: tcont, gemportMax: gemport, vportMax: vport, srvportMax: srvport } = preInfo;
          // 绑定多vlan
          const result = await zte.onuBindVlan(olt.oltHardVersion, ponIndex, onuIndex, vlan, tcont, dba, gemport, vport, srvport, upstream, downstream, this);
          return result;
        },
        HUAWEI: async () => {
          console.log('huawei', olt.oltHardVersion, ponIndex, onuIndex, vlan, upstream, downstream);
          const options = new ConnectOption(olt.oltIP, olt.initCommunity, olt.snmpUDPPort, 162, true, true, olt.telnetTCPPort, olt.oltManagementPassword, olt.oltTelnetUsername, olt.oltTelnetPassword, olt.systemName, olt.RZUsername, olt.RZPassword,olt.telnetProxySwitch);
          const hw = new HWOLT(options);
          const dbaInfo = await hw.getDBAProfileList(this);
          console.log('查询到DBA数据:', dbaInfo);
          const lineProfileResult = await this.ctx.model.LineProfile.findOne({ _id: lineProfile });
          const lineprofileName = lineProfileResult.name;
          // srvprofile
          const srvProfileResult = await this.ctx.model.OnuProfile.findOne({ _id: srvProfile });
          const srvprofileName = srvProfileResult.Pname;
          return false;
        },
      };
      return Brand[brandName] && Brand[brandName].call(this);
    };
    return Strategy.call(this, olt.oltType, olt);
  }
  async getONUDetails(params) {
    const onuResult = await this.ctx.model.OnuList.findOne({ _id: params.id });
    const oltResult = await this.ctx.model.Olt.findOne({ _id: onuResult.oltId });
    const options = new ConnectOption(oltResult.oltIP, oltResult.initCommunity, oltResult.snmpUDPPort, 162, true, true, oltResult.telnetTCPPort, oltResult.oltManagementPassword, oltResult.oltTelnetUsername, oltResult.oltTelnetPassword, oltResult.systemName, oltResult.RZUsername, oltResult.RZPassword,oltResult.telnetProxySwitch);
    try {
      const ONU = {
        async HUAWEI(options, onu) {
          const hw = new HWOLT(options);
          const res = await hw.getONUDetails(onu.PONindex, onu.ONUindex, this);
          return res;
        },
        async ZTE(options, onu) {
          const zte = new ZTEOLT(options);
          const onuAddress = onu.PONindex + ':' + onu.ONUindex;
          const res = await zte.getONUDetails(onuAddress, oltResult.oltHardVersion, this);
          return res;
        },
      };
      const result = ONU[oltResult.oltType] && (await ONU[oltResult.oltType].call(this, options, onuResult));
      return result;
    } catch (error) {
      console.log(error);
      throw error;
    }
  }

  async onuManagement(type,id) {
    const onuResult = await this.ctx.model.OnuList.findOne({ _id: id });
    const oltResult = await this.ctx.model.Olt.findOne({ _id: onuResult.oltId });
    const options = new ConnectOption(oltResult.oltIP, oltResult.initCommunity, oltResult.snmpUDPPort, 162, true, true, oltResult.telnetTCPPort, oltResult.oltManagementPassword, oltResult.oltTelnetUsername, oltResult.oltTelnetPassword, oltResult.systemName, oltResult.RZUsername, oltResult.RZPassword,oltResult.telnetProxySwitch);
    try {
      const ONU = {
        async HUAWEI(options, onu, method) {
          const hw = new HWOLT(options);
          const res = hw[method] && await hw[method](onu.PONindex, onu.ONUindex, this);
          return res;
        },
        async ZTE(options, onu, method) {
          const zte = new ZTEOLT(options);
          const onuAddress = onu.PONindex + ':' + onu.ONUindex;
          const res = zte[method]&&await zte[method](onu.PONindex, onu.ONUindex, oltResult.oltHardVersion, this);
          return res;
        },
      }
      const result = ONU[oltResult.oltType] && (await ONU[oltResult.oltType].call(this, options, onuResult, type));
      return result;
    } catch (error) {
      throw error;
    }
  }
  async setCatvState(params) {
    const result = {
      msg: '',
      flag: false,
    };
    try {
      const oltInformation = await this.ctx.model.Olt.findOne({
        _id: params.OltId,
      });
      const onuResult = await this.ctx.model.OnuList.findOne({
        _id:params.id
      })
      //设置onucatv状态
      await setCatvState(oltInformation,onuResult,params.catvstate,this)
      //设置数据库状态
      await this.ctx.model.OnuList.updateOne({_id:params.id},{$set:{
        catvstate:params.catvstate,
      }})
      result.msg = "setCatvState successful"
      result.flag = true
      return result
    } catch (error) {
      result.msg = "setCatvState fail,"+error
      result.flag = false
      return result
    }
    // const result = await setCatvState(params)
    // return result
  }
}
async function refreshONU(oltresult, me) {
  // 拿到onu列表
  let onuarr,
    onulist;
  const result = {
    msg: '',
    flag: true,
  };
  const options = new ConnectOption(oltresult.oltIP, oltresult.snmpReadOnlyCommunity, oltresult.telnetTCPPort, 162, true, true, oltresult.telnetTCPPort, oltresult.oltManagementPassword, oltresult.oltTelnetUsername, oltresult.oltTelnetPassword, oltresult.systemName || '', oltresult.snmpReadWriteCommunity,oltresult.RZUsername, oltresult.RZPassword,oltresult.telnetProxySwitch);
  try {
    switch (oltresult.oltType) {
      case 'OPTICTIMES':
        var xd = new XDOLT(options);
        onuarr = await xd.getOnuList();
        var onuinfo = await xd.getONUDetailInfo();
        var onusn = await xd.getONUSN();
        break;
      case 'ZTE':
        var zte = new ZTEOLT(options);
        onuarr = await zte.getOnuList(oltresult.oltHardVersion, me);
        break;
      case 'HUAWEI':
        var hw = new HWOLT(options);
        onuarr = await hw.getOnuList(oltresult.oltHardVersion, me);
        break;
      case 'XINGELIN':
        var xgl = new XGLOLT(options);
        onuarr = await xgl.getOnulist(oltresult.oltHardVersion, me);
        break;
    }
  } catch (error) {
    result.msg = oltresult.oltIP + 'getONUList fail';
    result.flag = false;
    return result;
  }
  try {
    switch (oltresult.oltType) {
      case 'OPTICTIMES':
        onulist = await mergeField(onuarr, onuinfo, onusn);
        break;
      case 'ZTE':
        onulist = await zte.getONUDetailInfo(onuarr, oltresult.oltHardVersion, me);
        break;
      case 'HUAWEI':
        onulist = await hw.getONUDetailInfo(onuarr, oltresult.oltHardVersion, me);
        break;
      case 'XINGELIN':
        onulist = await xgl.getONUDetailInfo(onuarr, oltresult.oltHardVersion, me);
        break;
    }
    // 然后遍历拿到每个onu detailinfo 存入数据库
    await addonulist(oltresult.id, onulist, me);
    result.msg = oltresult.oltIP + 'onurefresh successful';
    result.flag = true;
    return result;
  } catch (error) {
    result.msg = oltresult.oltIP + 'onurefresh fail';
    result.flag = false;
    return result;
  }
}
// 添加onu到数据库
async function addonulist(oltId, onulist, me) {
  const Op = me.ctx.model.Sequelize.Op;
  const onlyindexArr = [];
  for (let i = 0; i < onulist.length; i++) {
    onlyindexArr.push(onulist[i].onlyindex);
    // 删除不一样的onu
    const result = await me.ctx.model.Onu.findOne({ where: { oltId, onlyindex: onulist[i].onlyindex } });
    if (!result) {
      onulist[i].id = ulid.ulid();
      onulist[i].oltId = oltId;
      onulist[i].acsSupport = false;
      onulist[i].tid = me.ctx.session.admin.tid;
      await me.ctx.model.Onu.create(onulist[i]);
    } else {
      if (result.SN != onulist[i].SN) {
        await me.ctx.model.Onu.destroy({ where: { id: result.id } });
        onulist[i].id = ulid.ulid();
        onulist[i].oltId = oltId;
        onulist[i].acsSupport = false;
        onulist[i].tid = me.ctx.session.admin.tid;
        await me.ctx.model.Onu.create(onulist[i]);
      } else {
        await me.ctx.model.Onu.update({ ONUname: onulist[i].ONUname, state: onulist[i].state }, { where: { id: result.id } });
      }
    }
  }
  // 删除不存在的onu
  await me.ctx.model.Onu.destroy({
    where: {
      onlyindex: {
        [Op.notIn]: onlyindexArr,
      },
      oltId,
    },
  });
}
// 芯德拼接字段
async function mergeField(onuarr, onuinfo, onusn) {
  const onulist = [];
  for (var i = 0; i < onuarr.length; i++) {
    switch (onuarr[i].state) {
      case '0':
        onuarr[i].state = 'logging';
        break;
      case '1':
        onuarr[i].state = 'los';
        break;
      case '2':
        onuarr[i].state = 'syncMib';
        break;
      case '3':
        onuarr[i].state = 'working';
        break;
      case '4':
        onuarr[i].state = 'dyingGasp';
        break;
      case '5':
        onuarr[i].state = 'authFail';
        break;
      case '6':
        onuarr[i].state = 'OffLine';
        break;
    }
    for (var j = 0; j < onuinfo.length; j++) {
      if (onuarr[i].PONindex == onuinfo[j].PONindex && onuarr[i].ONUindex == onuinfo[j].ONUindex) {
        onulist.push({
          onlyindex: onuarr[i].PONindex + ':' + onuarr[i].ONUindex,
          PONindex: onuarr[i].PONindex,
          ONUindex: onuarr[i].ONUindex,
          state: onuarr[i].state,
          ONUname: onuinfo[i].ONUname,
        });
      }
    }
  }
  for (var i = 0; i < onulist.length; i++) {
    for (var j = 0; j < onusn.length; j++) {
      if (onulist[i].PONindex == onusn[j].PONindex && onulist[i].ONUindex == onusn[j].ONUindex) {
        onulist[i].SN = onusn[i].SN;
      }
    }
  }
  console.log(onulist);
  return onulist;
}
async function setCatvState(oltInformation,onuResult,catvstate,me){
  const options = new ConnectOption(
    oltInformation.oltIP,
    oltInformation.initCommunity,
    oltInformation.snmpUDPPort,
    162,
    true,
    true,
    oltInformation.telnetTCPPort,
    oltInformation.oltManagementPassword,
    oltInformation.oltTelnetUsername,
    oltInformation.oltTelnetPassword,
    oltInformation.systemName,
    oltInformation.RZUsername,
    oltInformation.RZPassword,
    oltInformation.telnetProxySwitch
  );
  let result
  try {
    switch (oltInformation.oltType) {
      case 'ZTE':
        const zte = new ZTEOLT(options);
        result = await zte.setCatvState(oltInformation.oltHardVersion,onuResult,catvstate,me)
        break;
      case 'HUAWEI':
        const hw = new HWOLT(options);
        result = await hw.setCatvState(onuResult,catvstate,me)
        break;
    }
    return result;
  } catch (error) {
    throw error;
  }
}
module.exports = OnuService;
